package timbap.visualizer.api.plugin.container;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import timbap.visualizer.api.context.messaging.TimeCodeListener;
import timbap.visualizer.api.model.TimeCode;
import timbap.visualizer.api.plugin.Plugin;

/**
 * The <code>AbstractModeControlSwitch</code> provides a
 * common base implementation of the <code>ModeControlSwitch</code>
 * interface that should be used by all plugin controllable switches
 * that also dispatch a timecode to their plugins.
 *
 * @author  Andreas Pabst
 * @see     timbap.visualizer.api.plugin.container.ModeControlSwitch
 * @see     timbap.visualizer.api.plugin.container.AbstractPluginControllableSwitch
 * @see     timbap.visualizer.api.context.messaging.TimeCodeListener
 */
public abstract class AbstractModeControlSwitch extends AbstractPluginControllableSwitch implements ModeControlSwitch {

	private static final Log LOG = LogFactory.getLog(AbstractModeControlSwitch.class);
    private static final int STALE_TIME_IN_MS = 1000;

    private TimeCodeListener timeCodeListener;
    boolean hasTimeCode = false; 

    private long lastReceiveTime;

   
    public void publishTimeCode(TimeCode pTimeCode) {
        if (timeCodeListener != null) {
            timeCodeListener.timeCodeUpdated(pTimeCode);
        }
    }

    public void setTimeCodeListener(TimeCodeListener pTimeCodeListener) {
        timeCodeListener = pTimeCodeListener;   
    }
    
    
   public void timeCodeUpdated(TimeCode pTimeCode) {
    	if (!hasTimeCode) {
    		hasTimeCode = true;
    	}
        lastReceiveTime = System.currentTimeMillis();
        publishTimeCode(pTimeCode);
    }

	public boolean hasTimeCode() {
		return hasTimeCode;
	}

    public boolean isTimeCodeValid() {
        return hasTimeCode;
    }

    public boolean isTimeCodeStale() {
        return !hasTimeCode || (System.currentTimeMillis() - lastReceiveTime > STALE_TIME_IN_MS);
    }

    @Override
    public void addPlugin(Plugin pPlugin) {
        super.addPlugin(pPlugin);
        if (pPlugin instanceof TimeCodeListener) {
            TimeCodeListener tController = (TimeCodeListener)pPlugin;
            if (getPlugins().size() == 1) {
                setTimeCodeListener(tController);
            }
        }
    }

    @Override
    public void removePlugin(Plugin pPlugin) {
        super.removePlugin(pPlugin);
        if (pPlugin instanceof TimeCodeListener) {
            if (getPlugins().size() == 0) {
                setTimeCodeListener(null);
            }
        }
    }

    @Override
    public void handlePluginSwitchCommand(PluginSwitchCommand pPluginSwitchCommand) {
        
    	super.handlePluginSwitchCommand(pPluginSwitchCommand);
        Plugin tActivePlugin = getActivePlugin();
        if (tActivePlugin instanceof TimeCodeListener) {
            setTimeCodeListener((TimeCodeListener)tActivePlugin);
        } else {
            LOG.warn("Activated child plugin " + tActivePlugin
                    + " of " + ModeControlSwitch.class.getSimpleName() + " " + this
                    + " does not implement the " + TimeCodeListener.class.getSimpleName() + " interface.");
        }
    }

    @Override
    public void toNext() {
        Plugin tPlugin = getActivePlugin();
        if (tPlugin instanceof ModeController) {
            ModeController tActiveModeController = (ModeController) tPlugin;
            ModeController tNextModeController = tActiveModeController.getNextModeController();
            int tNextPluginIndex = getPlugins().indexOf(tNextModeController);
            if (tNextPluginIndex > -1) {
                to(tNextPluginIndex);
            }
        }
    }

    @Override
    public void toPrevious() {
        Plugin tPlugin = getActivePlugin();
        if (tPlugin instanceof ModeController) {
            ModeController tActiveModeController = (ModeController) tPlugin;
            ModeController tPrevModeController = tActiveModeController.getPreviousModeController();
            int tPrevPluginIndex = getPlugins().indexOf(tPrevModeController);
            if (tPrevPluginIndex > -1) {
                to(tPrevPluginIndex);
            }
        }
    }
}
